@file:Suppress("unused")

package com.hua.giftool.utils

import android.Manifest
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.provider.Settings
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.net.toUri
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import com.hua.giftool.utils.PermissionRequestManager.addPermissionRequest
import com.hua.giftool.utils.PermissionRequestManager.registerForRequestPermission


/**
 * 原生权限请求实现
 * @param permission String 需要请求的权限
 * @param whenDenied 当权限被拒绝时执行的操作
 * @param deniedAtLast 当权限最终被拒绝时的操作
 * @param tryBlock 尝试以已授权的方式执行tryBlock，如果成功，认为已授权
 * @param onGranted 已授权的操作
 * @receiver AppCompatActivity
 */
fun <T : AppCompatActivity> T.checkOrRequestPermission(
    permission: String,
    whenDenied: (jump: () -> Unit) -> Unit,
    deniedAtLast: () -> Unit = {},
    tryBlock: (() -> Boolean)? = null,
    onGranted: () -> Unit = {}
) = this.checkOrRequestPermission(
    permissions = mutableListOf(permission), whenDenied, deniedAtLast, tryBlock, onGranted
)


/**
 * 原生权限请求实现
 * @param permissions MutableList<String> 需要请求的权限
 * @param whenDenied 当权限被拒绝时执行的操作
 * @param deniedAtLast 当权限最终被拒绝时的操作
 * @param tryBlock 尝试以已授权的方式执行tryBlock，如果成功，认为已授权
 * @param onGranted 已授权的操作
 * @receiver AppCompatActivity
 */
fun <T : AppCompatActivity> T.checkOrRequestPermission(
    permissions: MutableList<String>,
    whenDenied: (jump: () -> Unit) -> Unit,
    deniedAtLast: () -> Unit = {},
    tryBlock: (() -> Boolean)? = null,
    onGranted: () -> Unit = {}
) {
    //如果是6.0以下，则默认已经获取权限
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
        onGranted()
        return
    }
    // 检查是否已授权 ContextCompat.checkSelfPermission不够准确，部分权限有可能返回未授权，但是设置页面显示已授权，需要tryBlock的结果辅助验证
    val notGrantedPermissions = permissions.filter {
        ContextCompat.checkSelfPermission(this, it) == PackageManager.PERMISSION_DENIED ||
                checkSelfPermission(it) == PackageManager.PERMISSION_DENIED
    }

    when {
        //全部权限均已授权
        notGrantedPermissions.isEmpty() -> {
            
            // 所有权限都已授权
            onGranted()
        }
        //尝试按照已经获取到权限的情况执行相关操作，如果成功，说明有权限
        tryBlock != null && PermissionRequestManager.tryPermissionLimitedApi(tryBlock) -> {
            
            onGranted()
        }
        //确实权限被拒绝的情况再申请权限
        else -> {
            
            //存放权限请求的回调到manager中
            addPermissionRequest(
                PermissionRequestManager.PermissionRequest(
                    this,
                    notGrantedPermissions as MutableList<String>,
                    onGranted,
                    tryBlock,
                    whenDenied,
                    deniedAtLast
                )
            )
        }
    }
}


/**
 * 管理权限请求回调
 */
private object PermissionRequestManager {
    const val TAG = "PermissionRequestManager"
    private const val COMMON_REQUEST_CODE = 1001

    private var isPermissionRequesting: Boolean = false
    private var isJumpingForRequest: Boolean = false

    /**
     * 权限请求数据类
     */
    data class PermissionRequest(
        val activity: AppCompatActivity,
        val permissions: MutableList<String>,
        val onGranted: () -> Unit,
        val tryBlock: (() -> Boolean)? = null,
        val whenDenied: (jump: () -> Unit) -> Unit,
        val deniedAtLast: () -> Unit
    )

    /**
     * 权限请求列表
     */
    private val permissionRequestList: MutableList<PermissionRequest> = mutableListOf()

    private var requestLauncher: ActivityResultLauncher<Array<String>>? = null


    /**
     * 添加权限请求
     */
    fun addPermissionRequest(request: PermissionRequest) {
        permissionRequestList.add(request)
        
        //防止发起多次并行请求
        if (!isPermissionRequesting) {
            startRequest()
        }
    }

    /**
     * 尝试使用权限限制的api，如果失败或block的结果为false则返回false
     */
    fun tryPermissionLimitedApi(block: (() -> Boolean)): Boolean {
        return try {
            block()
        } catch (e: SecurityException) {
            
            false
        } catch (e: Exception) {
            
            false
        }
    }

    /**
     * 启动权限请求
     */
    private fun startRequest() {
        if (permissionRequestList.isEmpty()) {
            return
        }
        if (permissionRequestList.first().permissions.shouldCheckPermission) {
            
            isPermissionRequesting = true
            startRequestPermission()
        } else {
            
            permissionRequestList.first().onGranted().also { stopThisRequest() }
        }
    }

    /**
     * 启动权限请求
     */
    private fun startRequestPermission() {
        //向系统申请权限，这里不一定能够获取成功，在onRequestResult中进行判断结果
        

        requestLauncher?.launch(permissionRequestList.first().permissions.toTypedArray())
    }

    /**
     * 生命周期监听
     */
    fun <T : AppCompatActivity> T.registerForRequestPermission() {
        
        //如果在权限请求过程中跳转了新的页面并进行了权限请求，把上一个请求停掉
        stopThisRequest()
        
        requestLauncher = registerForActivityResult(
            ActivityResultContracts.RequestMultiplePermissions()
        ) { result ->
            onRequestResult(result)
        }
        lifecycle.addObserver(object : LifecycleEventObserver {
            override fun onStateChanged(
                source: LifecycleOwner,
                event: Lifecycle.Event
            ) = when (event) {
                Lifecycle.Event.ON_CREATE -> {}
                Lifecycle.Event.ON_START -> {}
                Lifecycle.Event.ON_RESUME -> {
                    //当权限被拒绝，引导用户去设置界面打开权限后，在onResume中重新检查权限
                    
                    recheckPermission()
                }

                Lifecycle.Event.ON_PAUSE -> {}
                Lifecycle.Event.ON_STOP -> {}
                Lifecycle.Event.ON_DESTROY -> {
                    
                    stopThisRequest()
                    requestLauncher?.unregister()
                    requestLauncher = null
                    source.lifecycle.removeObserver(this)
                }

                else -> {}
            }
        })
    }


    /**
     * 检查当前安卓版本是否高于指定版本
     */
    private fun needCheckPermissionAbove(version: Int): Boolean = Build.VERSION.SDK_INT >= version

    /**
     * 权限列表，判断是否需要跳过权限检查，针对与某些权限在特定版本以下不需要去申请的情况
     */
    private val MutableList<String>.shouldCheckPermission: Boolean
        get() = any { permission ->
            when (permission) {
                //精确闹钟权限
                Manifest.permission.SCHEDULE_EXACT_ALARM -> needCheckPermissionAbove(Build.VERSION_CODES.S)     //API31
                //管理外部存储
                Manifest.permission.MANAGE_EXTERNAL_STORAGE -> needCheckPermissionAbove(Build.VERSION_CODES.R)  //API30
                //TODO 在这里添加其他需要特定版本的权限
                else -> true
            }
        }

    /**
     * 结束当前请求
     */
    private fun stopThisRequest() {
        if (isPermissionRequesting) {
            permissionRequestList.removeAt(0)
            isPermissionRequesting = false
            isJumpingForRequest = false
            if (!permissionRequestList.isEmpty()) {
                //启动下一个请求
                startRequest()
            }
        }
    }


    /**
     * 权限请求结果回调
     */
    private fun onRequestResult(map: Map<String, Boolean>) {
        if (isPermissionRequesting) {
            
            if (map.all { it.value }) {
                permissionRequestList.first().onGranted().also { stopThisRequest() }
            } else {
                permissionRequestList.first().whenDenied(whenDeniedBlock)
            }
        }
    }

    /**
     * 直接的权限请求失败时跳转到权限设置页
     */
    private val whenDeniedBlock = block@{
        isJumpingForRequest = true
        val context = permissionRequestList.first().activity
        val permissionsList = permissionRequestList.first().permissions
        when {
            //首先尝试跳转到具体的权限设置页面
            jumpToSpecificPermission(context, permissions = permissionsList) -> {
                
                return@block
            }
            //跳转不成功则尝试跳转到当前应用的权限设置界面
            startAppPermissionSettings(context) -> {
                
                return@block
            }
            //跳转不成功则尝试跳转到当前应用的详细设置界面
            startAppSettings(context) -> {
                
                return@block
            }
            //都不成功则认为权限被拒绝
            else -> {
                
                permissionRequestList.first().deniedAtLast().also { stopThisRequest() }
            }
        }
    }


    /**
     * 在onResume中重新检查权限
     */
    fun recheckPermission() {
        // 检查请求结果
        if (isPermissionRequesting && isJumpingForRequest) {
            val notGrantedPermissions = permissionRequestList.first().permissions.filter {
                ContextCompat.checkSelfPermission(
                    permissionRequestList.first().activity, it
                ) == PackageManager.PERMISSION_DENIED
            }

            if (notGrantedPermissions.isEmpty()) {
                // 所有权限都已授权
                
                permissionRequestList.first().onGranted()
            } else if (permissionRequestList.first().tryBlock != null
                && permissionRequestList.first().tryBlock!!.invoke()
            ) {
                
                permissionRequestList.first().onGranted()
            } else {
                // 有权限未授权
                
                permissionRequestList.first().deniedAtLast()
            }
            stopThisRequest()
        }
    }

    /**
     * 尝试跳转到具体权限设置页
     * @param context Context
     * @param permissions 权限
     */
    fun jumpToSpecificPermission(
        context: Context,
        permissions: MutableList<String>,
        settingsPackage: String = "com.android.settings"
    ): Boolean {
        if (permissions.isEmpty()) {
            return false
        }

        val intent = Intent()
        intent.action = permissions.permissionsIntentAction
        intent.addCategory(Intent.CATEGORY_DEFAULT)
        intent.data = ("package:" + context.packageName).toUri()
        if (settingsPackage.isNotEmpty()) intent.setPackage(settingsPackage)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            val uri = Uri.fromParts("package", context.packageName, null)
            intent.data = uri
        }
        return try {
            context.startActivity(intent)
            true
        } catch (e: Exception) {
            e.printStackTrace()
            
            if (settingsPackage.isNotEmpty()) jumpToSpecificPermission(context, permissions, "")
            else false
        }
    }


    /**
     * 根据权限跳转不同界面
     * TODO 添加新的权限后需要在此处添加跳转的action
     * @receiver MutableList<String>
     */
    private val MutableList<String>.permissionsIntentAction: String
        @SuppressLint("InlinedApi") get() = when {
            this containsAnyIn mutableListOf(
                Manifest.permission.SCHEDULE_EXACT_ALARM
            ) -> Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM

            this containsAnyIn mutableListOf(
                Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.MANAGE_EXTERNAL_STORAGE
            ) -> if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION
            else Settings.ACTION_INTERNAL_STORAGE_SETTINGS

            this containsAnyIn mutableListOf(
                Manifest.permission.SYSTEM_ALERT_WINDOW
            ) -> Settings.ACTION_MANAGE_OVERLAY_PERMISSION

            this containsAnyIn mutableListOf(
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.ACCESS_COARSE_LOCATION
            ) -> Settings.ACTION_LOCATION_SOURCE_SETTINGS

            this containsAnyIn mutableListOf(
                Manifest.permission.CHANGE_WIFI_STATE,
                Manifest.permission.ACCESS_WIFI_STATE,
                Manifest.permission.CHANGE_NETWORK_STATE,
                Manifest.permission.ACCESS_NETWORK_STATE
            ) -> Settings.ACTION_WIFI_SETTINGS

            else -> Settings.ACTION_APPLICATION_DETAILS_SETTINGS
        }

    /**
     * 判断两个集合是否包含相同的元素
     */
    private infix fun MutableList<*>.containsAnyIn(list: MutableList<*>): Boolean {
        val set = this.toHashSet()
        return list.any { set.contains(it) }
    }

    /**
     * 跳转到当前应用的设置界面
     * @param context Context
     */
    fun startAppSettings(context: Context, settingsPackage: String = "com.android.settings"): Boolean = try {
        val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
        if (settingsPackage.isNotEmpty()) intent.setPackage(settingsPackage)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            intent.putExtra(Intent.EXTRA_PACKAGE_NAME, context.packageName)
        }
        intent.data = ("package:" + context.packageName).toUri()
        context.startActivity(intent)
        true
    } catch (e: Exception) {
        
        if (settingsPackage.isNotEmpty()) startAppSettings(context, "")
        else false
    }

    /**
     * 尝试跳转到当前应用的权限设置界面
     * @param context Context
     */
    private fun startAppPermissionSettings(
        context: Context,
        settingsPackage: String = "com.android.settings"
    ): Boolean = try {
        val intent = Intent("android.settings.APP_PERMISSIONS_SETTINGS")
        intent.data = ("package:" + context.packageName).toUri()
        if (settingsPackage.isNotEmpty()) intent.setPackage(settingsPackage)
        context.startActivity(intent)
        true
    } catch (e: Exception) {
        
        if (settingsPackage.isNotEmpty()) startAppPermissionSettings(context, "")
        else false
    }
}

fun <T : AppCompatActivity> T.initPermissionManager() {
    registerForRequestPermission()
}